package com.trilogy.fs.raptor.clustering;

import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @author <a href="razvan.surdulescu@post.harvard.edu">Razvan Surdulescu</a>, Copyright (c) 2003
 */
public class DotCanvas extends JPanel {
    private static final Color[] COLORS = new Color[] {
        Color.blue, Color.cyan, Color.gray, Color.green, Color.magenta,
        Color.orange, Color.pink, Color.red, Color.yellow
    };

    private DotFrame m_frame;
    private List m_dots = new ArrayList();
    private List m_clusters = new ArrayList();

    public DotCanvas(DotFrame frame) {
        m_frame = frame;

        addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                m_clusters.clear();
                m_dots.add(new Dot(e.getX(), e.getY()));
                repaint();
            }
        });

        addMouseMotionListener(new MouseMotionAdapter() {
            public void mouseDragged(MouseEvent e) {
                m_clusters.clear();
                m_dots.add(new Dot(e.getX(), e.getY()));
                repaint();
            }
        });
    }

    public void clear() {
        m_dots.clear();
        m_clusters.clear();
        repaint();
    }

    public void generate(int clusterCount, int pointCount) {
        m_clusters.clear();
        for (int i = 0; i < clusterCount; i++) {
            int x = (int) (getWidth() * Math.random());
            int y = (int) (getHeight() * Math.random());

            for (int j = 0; j < pointCount; j++) {
                m_dots.add(new Dot((int) (x + 10 - 20 * Math.random()), (int) (y + 10 - 20 * Math.random())));
            }
        }
        repaint();
    }

    public void paint(Graphics g) {
        m_frame.updatePointCount(m_dots.size());

        g.setColor(Color.white);
        g.fillRect(0, 0, getWidth(), getHeight());

        g.setColor(Color.black);
        g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);

        if (m_clusters.isEmpty()) {
            for (Iterator iter = m_dots.iterator(); iter.hasNext();) {
                Dot dot = (Dot) iter.next();
                g.fillOval(dot.getX() - 1, dot.getY() - 1, 3, 3);
            }
        } else {
            int color = 0;
            for (Iterator clusters = m_clusters.iterator(); clusters.hasNext();) {
                List cluster = (List) clusters.next();

                g.setColor(COLORS[color++]);
                if (color >= COLORS.length) {
                    color = 0;
                }

                for (Iterator dots = cluster.iterator(); dots.hasNext();) {
                    Dot dot = (Dot) dots.next();
                    g.fillOval(dot.getX() - 1, dot.getY() - 1, 3, 3);
                }

                drawBoundingBox(cluster, g);
            }
        }
    }

    private void drawBoundingBox(List cluster, Graphics g) {
        int minX = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE;
        int minY = Integer.MAX_VALUE, maxY = Integer.MIN_VALUE;

        for (Iterator dots = cluster.iterator(); dots.hasNext(); ) {
            Dot dot = (Dot) dots.next();
            if (dot.getX() < minX) {
                minX = dot.getX();
            }

            if (dot.getX() > maxX) {
                maxX = dot.getX();
            }
            if (dot.getY() < minY) {
                minY = dot.getY();
            }
            if (dot.getY() > maxY) {
                maxY = dot.getY();
            }
        }

        g.drawRect(minX - 5, minY - 5, maxX - minX + 10, maxY - minY + 10);
    }

    public List getDots() {
        return m_dots;
    }

    public List copyDots() {
        return (List) ((ArrayList)m_dots).clone();
    }

    public List getClusters() {
        return m_clusters;
    }

    public void setClusters(List clusters) {
        m_clusters = clusters;
        repaint();
    }
}
